home *** CD-ROM | disk | FTP | other *** search
- /*
-
- CTCPClient.c
- Superclass: CCollaborator
-
- The TCP client implementation for CTCP
-
- Copyright © NCSA, University of Illinois; June 3, 1992
- Eric Johnson, John Newlin and Igor Livshits
-
- This code may be used, modified, and distributed free of charge and obligation.
-
- */
-
- #include "CTCPClient.h"
-
- /*=====================*/
- /*===---------------===*/
-
- OSErr CTCPClient::ITCPClient(void)
- Begin
- CTCP* theStream= Null; // Local temporary storage
- OSErr error; // A possible error during initialization
-
- CCollaborator::ICollaborator();
-
- theStream= new CTCP; // Create our TCP stream
- error= theStream->ITCP();
-
- itsStream= theStream; // Remember our stream object
-
- return error;
- End
-
- /*===---------------===*/
-
- void CTCPClient::Dispose(void)
- Begin
- ForgetObject(itsStream);
-
- inherited::Dispose();
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::Create(Size streamLength)
- Begin
- itsStream->MakeStreamBuffer(streamLength);
-
- return itsStream->Create();
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::OpenConnection(void)
- Begin
- return itsStream->ActiveOpen();
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::WaitForConnection(void)
- Begin
- return itsStream->PassiveOpen();
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::SendData(Ptr data, Size length)
- Begin
- OSErr error; // A possible error condition
-
- itsStream->PlaceData(data, length); // Put our data into an out buffer
-
- retrySend:
- error= itsStream->Send(); // Send it
-
- if ( (error == kCommandTimeout) && (numRetries > 0) )
- {
- numRetries--;
- goto retrySend;
- }
-
- numRetries= Null;
-
- return itsStream->GetLastError();
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::ReceiveData(Ptr* data, Size* length)
- Begin // Wimpy and slow -- ignores the NoCopy alternative
- register Size newLength;
- OSErr error; // A possible error condition
-
- itsStream->CreateInputBuffer(data, *length);
-
- retryReceive:
- error= itsStream->Rcv();
-
- if ( (error == kCommandTimeout) && (numRetries > 0) )
- {
- numRetries--;
- goto retryReceive;
- }
-
- if (error == noErr)
- {
- newLength= itsStream->GetInputLength(); // Get the new data length
- if (newLength < *length)
- (*data)[newLength]= 0;
-
- *length= newLength;
- }
-
- numRetries= Null;
-
- return itsStream->GetLastError();
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::MyBufferReceiveData(Ptr data, Size* length)
- Begin
- OSErr error;
- Ptr theOldInputBuffer;
- Size theOldBufferLength;
-
- theOldInputBuffer= itsStream->GetInputBuffer();
- theOldBufferLength= itsStream->GetInputLength();
-
- FailOSErr( itsStream->SetInputBuffer(data, *length) );
-
- TRY
- {
- retryReceive:
- error= itsStream->Rcv();
-
- if ( (error == kCommandTimeout) && (numRetries > 0) )
- {
- --numRetries;
- goto retryReceive;
- }
-
- if (error == noErr)
- *length = itsStream->GetInputLength(); // How much did we get?
- else
- *length= Null; // An error invalidated any received data
-
- numRetries= Null;
- }
- CATCH
- {
- if (theOldInputBuffer != Null)
- FailOSErr( itsStream->SetInputBuffer(theOldInputBuffer, theOldBufferLength) );
- }
- ENDTRY;
-
- // Restore original buffer
- // if it is not Null
- if (theOldInputBuffer != Null)
- FailOSErr( itsStream->SetInputBuffer(theOldInputBuffer, theOldBufferLength) );
-
- return itsStream->GetLastError();
- End
-
- /*===--------------===*/
-
- OSErr CTCPClient::Close(void)
- Begin
- return itsStream->Close();
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::Abort(void)
- Begin
- return itsStream->Abort();
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::Quit(void)
- Begin
- return itsStream->Release();
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::Kill(void)
- Begin
- TCPiopb pb; // Our parameters
- ParmBlkPtr parameters= &pb; // Our parameters
-
- itsStream->GetParameters(¶meters);
-
- return PBKillIO(parameters, False);
- End
-
- /*===---------------===*/
-
- CTCP* CTCPClient::GetStream()
- Begin
- return itsStream;
- End
-
- /*===---------------===*/
-
- void CTCPClient::SetRetries(long count)
- Begin
- numRetries= count;
- End
-
- /*===---------------===*/
-
- void CTCPClient::SetAddress(char* name, ip_addr address, ip_port port)
- Begin
- if (!name || !address)
- FailOSErr( ResolveAddress(name, &address) );
-
- itsStream->SetDestination(name, address, port);
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::ResolveAddress(char* name, ip_addr* address)
- Begin
- hostInfoRec host; // Information about our host machine
- char done= Null; // Completion flag from DNR
- OSErr error= noErr; // A possible error condition
- CDNR* theResolver= Null; // Our DNR
-
- theResolver= new CDNR;
- theResolver->IDNR(Null);
-
- if (!name)
- {
- name= NewPtrClear(kNameLength);
-
- error= theResolver->AddressToName(*address, &host, Null, &done);
- }
- else
- {
- error= theResolver->StringToAddress(name, &host, Null, &done);
- *address= host.address[0];
- }
-
- ForgetObject(theResolver);
-
- if ((error == noErr) && (*(host.name)))
- {
- strncpy(name, host.name, kNameLength);
- name[strlen(name)-1]= Null; // Eliminate the trailing
- }
-
- return error;
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::GetLocalAddress(ip_addr* address)
- Begin
- OSErr error= noErr; // An error, if any
-
- retryMyIP:
- *address= this->itsStream->GetMyIPAddress();
- error= this->itsStream->GetLastError();
-
- if (error != noErr)
- {
- if ((numRetries > 0) && (error == kCommandTimeout))
- {
- this->numRetries--;
- goto retryMyIP;
- }
- else
- *address= Null;
- }
-
- this->numRetries= Null;
- return error;
- End
-
- /*===---------------===*/
-
- OSErr CTCPClient::GetLocalDotAddress(char* dotAddress)
- Begin
- OSErr error= noErr; // An error, if any
- ip_addr address; // Our address as a number
-
- error= this->GetLocalAddress(&address);
-
- if (error == noErr)
- {
- sprintf(dotAddress, "%lu.%lu.%lu.%lu",
- (address>>24),
- (address>>16)&0x000000ff,
- (address>> 8)&0x000000ff,
- (address )&0x000000ff);
- }
-
- return error;
- End
-
-
-
- /*===---------------===*/
-
-
- /*********************************
- * ReadData
- * This functions checks to see if there is data available from MacTCP and then
- * copies it into the internal buffer: itsBuffer.
- * You could probably set this up as an idle chore, but you will probably
- * want to force it once in awhile.
- *
- * Author: John Newlin
- * Date: 15 June 1992
- *
- * Modified 18 June 1992
- * Changed the flow so that even if there is no data waiting to be read, a
- * read call will be issued, and if it times out, oh well. This is because
- * of our relatively slow transfer times, and any other delays that may come
- * up.
- *
- **********************************/
-
- #define kMaxBufferSpace 32768L // Our buffer should never grow more than 32K
-
-
- void CTCPClient::ReadData (void)
- {
- TCPStatusPB theStatus; // Connection Status
- size_t bufSpaceLeft; // Amount of buffer space that is left.
- size_t bufSpaceNeeded; // How big we need to make the buffer.
- Size theBufSize;
- Size amtOfDataToRead; // amount of data to read in.
- Ptr tmpPtr;
- Ptr endPtr;
-
- TRY
- {
- if (this->itsBuffer == Null)
- {
- this->itsBuffer= NewHandle (1024); // Good initial size.
- tmpPtr= *(this->itsBuffer);
- *tmpPtr= '\0';
- }
-
-
- // Check if there is data available. If so read it in.
- FailOSErr (itsStream->Status (&theStatus));
- if (theStatus.amtUnreadData > 0)
- {
- // Lock down our buffer so we don't accidentally nuke ourselves.
- MoveHHi (this->itsBuffer);
- HLock (this->itsBuffer);
-
-
- // figure out how much buffer space we have left.
- tmpPtr= *(this->itsBuffer);
- theBufSize= GetHandleSize (this->itsBuffer);
- bufSpaceLeft= theBufSize - strlen (tmpPtr) - 1;
-
- // Make sure we have enough buffer space available
- if (bufSpaceLeft < theStatus.amtUnreadData)
- {
- // Figure out how much space we need to allocate
- bufSpaceNeeded= theStatus.amtUnreadData + strlen(tmpPtr) +1;
-
-
- if (bufSpaceNeeded > kMaxBufferSpace)
- bufSpaceNeeded= kMaxBufferSpace;
-
- HUnlock (this->itsBuffer);
- SetHandleSize (this->itsBuffer, bufSpaceNeeded);
- FailMemError();
- }
- HUnlock (this->itsBuffer);
- }
-
- // Now recalculate how much buffer space we have and read the data in
- MoveHHi (this->itsBuffer);
- HLock (this->itsBuffer);
- tmpPtr= *(this->itsBuffer);
- theBufSize= GetHandleSize (this->itsBuffer);
- bufSpaceLeft= theBufSize - strlen (tmpPtr) - 1;
-
-
- // Now read in the amount of data we can support.
- // No bitching about brackets, if you can't figure it out,
- // you shouldn't be reading it!!
- if (theStatus.amtUnreadData==0 || bufSpaceLeft<theStatus.amtUnreadData)
- amtOfDataToRead= bufSpaceLeft;
- else
- amtOfDataToRead= theStatus.amtUnreadData;
-
- endPtr= strrchr (tmpPtr, '\0');
- FailOSErr (this->MyBufferReceiveData (endPtr, &amtOfDataToRead));
- endPtr[amtOfDataToRead]= '\0';
-
- HUnlock (this->itsBuffer);
- }
- CATCH
- {
- HUnlock (this->itsBuffer);
- }
- ENDTRY;
-
- }
-
-
-
- /***********************************************
- * ReleaseBuffer
- * This function realeases the buffer allocated by ReadData.
- * This is useful is you only want part of the data that was
- * read in by ReadData.
- ***********************************************/
-
- void CTCPClient::ReleaseBuffer (void)
- {
- ForgetHandle (itsBuffer);
- FailMemError();
- }
-
-
-
- /*************************************************
- * GetLine
- * This function takes a pointer to a buffer and copies one line of
- * data into it. Includes the newline on the end.
- *
- * Note: This DOES null terminate your line.
- *************************************************/
-
- void CTCPClient::GetLine (Ptr line)
- {
- Ptr tmpPtr= Null;
- Ptr endPtr= Null;
- Size howLong= 0;
-
- howLong= this->HowLongNextLine();
- if (howLong > 0)
- {
- TRY
- {
- // Copy the data into the callers buffer.
- MoveHHi (this->itsBuffer);
- HLock (this->itsBuffer);
- tmpPtr= *(this->itsBuffer);
- strncpy (line, tmpPtr, howLong);
- line[howLong]= '\0';
-
- // Now we need to move the rest of the data
- endPtr= (tmpPtr+howLong);
- memmove (tmpPtr, endPtr, strlen (endPtr) + 1);
- HUnlock (this->itsBuffer);
- }
- CATCH
- {
- HUnlock (this->itsBuffer);
- }
- ENDTRY;
- }
- return;
- }
-
-
-
- /*********************************************
- * HowLongNextLine
- * This function figures out how many characters are then next line.
- * The length includes the new line.
- *
- * The functionality here is in question. If there is no newline should
- * I say how many characters are available up to the end of string, or should
- * I return Null.
- * If I agree to the first condition, then there must ALWAYS be a new line
- * if the sender wants the receiver (us) to get the data. The reason this
- * is in question is because there may be data available from MacTCP that
- * we have no stuck into itsBuffer yet.
- *
- * Maybe if we hit the case with no newline, we should call ReadData,
- * and then try it again. hmmmmmmm..... What do you think???
- *
- * Author: John Newlin
- * Date: 15 June 1992
- **********************************************/
-
- Size CTCPClient::HowLongNextLine (void)
- {
- Ptr tmpPtr;
- Ptr endPtr;
- Size length;
-
- if (this->itsBuffer == Null)
- {
- length= 0;
- }
- else
- {
- // Lock the buffer and put a pointer to the first character.
- MoveHHi (this->itsBuffer);
- HLock (this->itsBuffer);
- tmpPtr= *(this->itsBuffer);
-
- // Find the end of line character.
- endPtr= strchr (tmpPtr, '\n');
- if (endPtr == Null)
- length= strlen (tmpPtr);
- else
- {
- char tmpChar= *endPtr;
- *endPtr= '\0';
- length= strlen (tmpPtr) + 1;
- *endPtr= tmpChar;
- }
- }
-
- return length;
- }
-
- /*=====================*/